

module.exports = class MyPromise {
    // 标记：是否有onRejected
    #hasRejectHandler = false
    // 状态
    #status = 'pending'
    // 结果
    #result = null
    // 错误
    #error = null
    // 所有实例队列
    static instanceQueue = []
    // 所有事件队列
    static taskQueue = []
    // resolve调用
    #resolve = function (res) {
        // 如果状态没改变，那就改变状态并保存结果（promise状态只能更改一次）
        if (this.#status === 'pending') {
            this.#result = res
            this.#status = 'fulfilled'
        }
        this.#clearTaskStack()

    }
    // 与上面resolve同理
    #reject = function (err) {
        if (this.#status === 'pending') {
            this.#error = err
            this.#status = 'rejected'
        }
        this.#HostPromiseRejectionTracker()
        this.#clearTaskStack()

    }

    // HostPromiseRejectionTracker
    #HostPromiseRejectionTracker = function () {
        // 微任务：检测所有promise实例是否存在状态rejected但没有处理函数的，抛出警告
        queueMicrotask(() => {
            for (let i = 0; i < MyPromise.instanceQueue.length; i++) {
                if (MyPromise.instanceQueue[i].#status === 'rejected') {
                    if (!MyPromise.instanceQueue[i].#hasRejectHandler) console.warn('unhandler promise rejected')
                }
            }
        })
    }

    // NewPromiseResolveThenableJobTask
    #NewPromiseResolveThenableJobTask = function (resPromise, nextPromise) {
        // 微任务：调用promise的then去到promise的result并resolve新的promise
        queueMicrotask(() => {
            resPromise.then(res => {
                // resolve下一个promise
                nextPromise.#resolve(res)
            })
        })
    }

    // 用于清理事件队列的方法
    #clearTaskStack = function () {
        // 用于记录pending的promise
        let unfinishPs = []
        for (let i = 0; i < MyPromise.taskQueue.length; i++) {
            let item = MyPromise.taskQueue[i]
            // 如果已经resolve
            if (item.instance.#status === 'fulfilled') {
                // 创建微任务
                queueMicrotask(() => {
                    // 执行监听器
                    let res = item.onFulfilled(item.instance.#result)
                    // 如果监听器返回是个promise，应该在生产一个微任务，且取值
                    if (res instanceof MyPromise) {
                        // NewPromiseResolveThenableJobTask
                        this.#NewPromiseResolveThenableJobTask(res, item.next)
                    }
                    // 如果是个thenable对象，也要调用它的then拿到值，且then也会创建一个微任务（这里只是看着原生promise的表现进行猜测），但我们这里的res.then如果是thenable对象的话是不会创建微任务的，所以要手动加一个微任务
                    else if (res && res.then) {
                        res.then(res => {
                            queueMicrotask(() => {
                                // resolve下一个promise
                                item.next.#resolve(res)
                            })
                        })
                    }
                    else {
                        // resolve下一个promise
                        item.next.#resolve(res)
                    }
                })
            }
            // 如果已经reject
            else if (item.instance.#status === 'rejected') {
                // 创建微任务
                queueMicrotask(() => {
                    // 执行监听器
                    item.onRejected(item.instance.#error)
                    // resolve下一个promise
                    item.next.#resolve()
                })
            }
            else {
                // 否则按顺序返回队列
                unfinishPs.push(item)
            }
        }
        // 只留下pending的promise
        MyPromise.taskQueue = unfinishPs
    }

    // 构造器：
    constructor(cb = () => { }) {
        // 收集promise实例
        MyPromise.instanceQueue.push(this)
        // 同步执行回调函数
        cb(this.#resolve.bind(this), this.#reject.bind(this))

    }

    // then方法：
    then(onFulfilled = (e) => e, onRejected) {
        // 如果有onRejected处理函数，改变promise的标记状态
        if (onRejected) this.#hasRejectHandler = true
        let next = new MyPromise()
        // 1.添加两个监听器
        MyPromise.taskQueue.push({
            onRejected,
            onFulfilled,
            instance: this,
            next,
        })

        // 2.如果promise已经返回结果，那就执行对应的监听器
        if (this.#status === 'fulfilled') this.#resolve()
        if (this.#status === 'rejected') this.#reject()

        // 3.返回一个新的promise
        return next
    }

    catch(onRejected = err => err) {
        return this.then(undefined, onRejected)
    }

    finally(cb = e => e) {
        return this.then(cb, cb)
    }

    static resolve(e) {
        return new MyPromise(_ => _(e))
    }

    static reject(e) {
        return new MyPromise((resolve, _) => _(e))
    }
}